#ifndef PHOTONLIST_H_INCLUDED
#define PHOTONLIST_H_INCLUDED

#include "photon.h"

template <class T>
class LinkedList {
    struct Container {
        Container( void ) : previous( NULL ), next( NULL ) { }
        Container( const T & inc ) : data( inc ) { }
        T data;
        Container * previous;
        Container * next;
    };
public:
    class iterator {
    public:
        iterator( Container * ptr = NULL ) : data( ptr ) { }
        T & operator*( void ) { return data->data; }
        iterator & operator++( void ) { data = data->next; return *this; }
        iterator operator++( int ) { iterator temp = *this; data = data->next; return temp; }
        bool operator==( const iterator & pi ) const { return data == pi.data; }
        bool operator!=( const iterator & pi ) const { return data != pi.data; }
        friend class LinkedList;
    private:
        Container * data;
    };
    class const_iterator {
    public:
        const_iterator( const Container * ptr = NULL ) : data( ptr ) { }
        const T & operator*( void ) const { return data->data; }
        const_iterator & operator++( void ) { data = data->next; return *this; }
        const_iterator operator++( int ) { const_iterator temp = *this; data = data->next; return temp; }
        bool operator==( const const_iterator & pi ) const { return data == pi.data; }
        bool operator!=( const const_iterator & pi ) const { return data != pi.data; }
    private:
        const Container * data;
    };
    LinkedList( void ) { first.previous = NULL; first.next = &last; last.previous = &first; last.next = NULL; }
    LinkedList( const LinkedList<T> & );
    LinkedList<T> & operator=( const LinkedList<T> & );
    void add( const T & );
    void remove( const iterator & );
    iterator begin( void ) { return iterator( first.next ); }
    iterator end( void ) { return iterator( &last ); }
    const_iterator begin( void ) const { return const_iterator( first.next ); }
    const_iterator end( void ) const { return const_iterator( &last ); }
    void clear( void );
    ~LinkedList( void ) { clear(); };
private:
    Container first, last;
};

template <class T>
void LinkedList<T>::add( const T & data ) {
    Container * oldPrevious = last.previous;
    Container * newPhoton = new Container( data );

    oldPrevious->next = newPhoton;
    last.previous = newPhoton;
    newPhoton->previous = oldPrevious;
    newPhoton->next = &last;
}

template <class T>
void LinkedList<T>::remove( const iterator & iter ) {
    Container * oldNext = iter.data->next;
    Container * oldPrevious = iter.data->previous;

    oldPrevious->next = oldNext;
    oldNext->previous = oldPrevious;

    delete iter.data;
}

template <class T>
void LinkedList<T>::clear( void ) {
    iterator iter = begin();

    while ( iter != end() ) {
        remove( iter++ );
    }
}

template <class T>
LinkedList<T>::LinkedList( const LinkedList<T> & inc ) {
    first.previous = NULL;
    first.next = &last;
    last.previous = &first;
    last.next = NULL;

    *this = inc;
}

template <class T>
LinkedList<T> & LinkedList<T>::operator=( const LinkedList<T> & inc ){
    clear();

    LinkedList<T>::const_iterator iter = inc.begin();

    while( iter != inc.end() ) {
        add( *iter++ );
    }

    return *this;
}

#endif // PHOTONLIST_H_INCLUDED
